<template>
    <scroll-view 
      class="my-list"
      :style="{ height: height }"
      scroll-y
      @scrolltolower="handleLoadMore"
      @scroll="handleScroll"
      :refresher-enabled="enablePullRefresh"
      :refresher-triggered="refreshing"
      @refresherrefresh="handleRefresh"
    >
      <!-- 内容容器 -->
      <view class="list-container" :style="{ minHeight: `calc(${height} - 60rpx)` }">
        <view class="list-transition-group">
          <slot></slot>
        </view>
      </view>
      
      <!-- 空状态 -->
      <view v-if="list.length === 0 && !loading" class="empty-state fade-in">
        <image :src="emptyImage" mode="aspectFit"></image>
        <text>{{ emptyText }}</text>
      </view>
      
      <!-- 加载状态 -->
      <view v-if="enableLoadMore && list.length > 0" class="load-more">
        <view v-if="loading" class="loading-spinner">
          <view class="spinner"></view>
          <text>{{ loadingText }}</text>
        </view>
        <text v-else-if="hasMore" class="bounce-in">上拉加载更多</text>
        <text v-else class="fade-in">{{ noMoreText }}</text>
      </view>
    </scroll-view>
  </template>
  
  <script setup>
  import { ref, nextTick } from 'vue'
  
  // 定义props
  const props = defineProps({
    // 列表数据
    list: {
      type: Array,
      default: () => []
    },
    // 是否显示下拉刷新
    enablePullRefresh: {
      type: Boolean,
      default: true
    },
    // 是否显示上拉加载更多
    enableLoadMore: {
      type: Boolean,
      default: true
    },
    // 是否还有更多数据
    hasMore: {
      type: Boolean,
      default: true
    },
    // 是否正在加载
    loading: {
      type: Boolean,
      default: false
    },
    // 空状态提示文本
    emptyText: {
      type: String,
      default: '暂无数据'
    },
    // 空状态图片
    emptyImage: {
      type: String,
      default: '/static/empty.png'
    },
    // 加载中提示文本
    loadingText: {
      type: String,
      default: '正在加载...'
    },
    // 没有更多数据提示文本
    noMoreText: {
      type: String,
      default: '没有更多数据了'
    },
    // 下拉刷新提示文本
    refreshText: {
      type: String,
      default: '下拉可以刷新'
    },
    // 高度
    height: {
      type: String,
      default: '100vh'
    }
  })
  
  // 定义emit
  const emit = defineEmits(['loadmore', 'refresh'])
  
  // 下拉刷新状态
  const refreshing = ref(false)
  
  // 处理加载更多
  const handleLoadMore = () => {
    if (props.loading || !props.hasMore || !props.enableLoadMore) return
    emit('loadmore')
  }
  
  // 处理下拉刷新
  const handleRefresh = async () => {
    if (props.loading || !props.enablePullRefresh) return
    refreshing.value = true
    emit('refresh')
    // 等待父组件处理完刷新
    await nextTick()
    refreshing.value = false
  }
  
  // 供父组件调用，手动触发刷新
  const refresh = () => {
    handleRefresh()
  }
  
  // 处理滚动
  const handleScroll = (e) => {
    if (props.loading || !props.hasMore || !props.enableLoadMore) return
    
    const { scrollTop, scrollHeight } = e.detail
    const { height } = e.target
    
    // 当距离底部还有30%时就开始加载
    if (scrollTop + height > scrollHeight * 0.7) {
      emit('loadmore')
    }
  }
  
  // 暴露方法给父组件
  defineExpose({
    refresh
  })
  </script>
  
  <style>
  .my-list {
    background-color: #f8f8f8;
  }
  
  /* 内容容器样式 */
  .list-container {
    position: relative;
    width: 100%;
    box-sizing: border-box;
  }
  
  /* 列表内容动画 */
  .list-transition-group {
    position: relative;
    min-height: 100%;
  }
  
  /* 淡入动画 */
  .fade-in {
    animation: fadeIn 0.3s ease-out;
  }
  
  @keyframes fadeIn {
    from {
      opacity: 0;
      transform: translateY(20rpx);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }
  
  /* 弹入动画 */
  .bounce-in {
    animation: bounceIn 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
  }
  
  @keyframes bounceIn {
    from {
      opacity: 0;
      transform: scale(0.8);
    }
    to {
      opacity: 1;
      transform: scale(1);
    }
  }
  
  /* 加载动画 */
  .loading-spinner {
    display: flex;
    align-items: center;
    justify-content: center;
    /* padding: 30rpx 0; */
  }
  
  .spinner {
    width: 30rpx;
    height: 30rpx;
    margin-right: 20rpx;
    border: 3rpx solid #007AFF;
    border-top-color: transparent;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
  }
  
  @keyframes spin {
    from {
      transform: rotate(0deg);
    }
    to {
      transform: rotate(360deg);
    }
  }
  
  .empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 100rpx 0;
  }
  
  .empty-state image {
    width: 200rpx;
    height: 200rpx;
    margin-bottom: 20rpx;
    animation: float 3s ease-in-out infinite;
  }
  
  /* 漂浮动画 */
  @keyframes float {
    0%, 100% {
      transform: translateY(0);
    }
    50% {
      transform: translateY(-20rpx);
    }
  }
  
  .empty-state text {
    font-size: 28rpx;
    color: #999;
  }
  
  .load-more {
    text-align: center;
    /* padding: 30rpx 0; */
    color: #999;
    font-size: 24rpx;
    height: 60rpx;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  
  /* 下拉刷新动画 */
  ::-webkit-scrollbar {
    width: 0;
    height: 0;
    background-color: transparent;
  }
  </style> 